package com.jzo2o.health.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.trade.NativePayApi;
import com.jzo2o.api.trade.TradingApi;
import com.jzo2o.api.trade.dto.request.NativePayReqDTO;
import com.jzo2o.api.trade.dto.response.NativePayResDTO;
import com.jzo2o.api.trade.dto.response.TradingResDTO;
import com.jzo2o.api.trade.enums.PayChannelEnum;
import com.jzo2o.api.trade.enums.TradingStateEnum;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.model.CurrentUserInfo;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.NumberUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.constant.RedisConstants;
import com.jzo2o.health.constant.TradeConstants;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.model.UserThreadLocal;
import com.jzo2o.health.model.domain.*;
import com.jzo2o.health.model.dto.OrderCountDTO;
import com.jzo2o.health.model.dto.request.OrdersCancelReqDTO;
import com.jzo2o.health.model.dto.request.OrdersPageQueryReqDTO;
import com.jzo2o.health.model.dto.request.PlaceOrderReqDTO;
import com.jzo2o.health.model.dto.response.*;
import com.jzo2o.health.properties.TradeProperties;
import com.jzo2o.health.service.*;
import com.jzo2o.mysql.utils.PageUtils;
import com.jzo2o.redis.helper.CacheHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.jzo2o.common.constants.ErrorInfo.Code.TRADE_FAILED;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author itcast
 * @since 2023-11-02
 */
@Slf4j
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersService {
    @Resource
    private ISetmealService setmealService;
    @Resource
    private IMemberService memberService;
    @Resource
    private IReservationSettingService reservationSettingService;
    @Resource
    private CacheHelper cacheHelper;
    @Resource
    private TradeProperties tradeProperties;
    @Resource
    private NativePayApi nativePayApi;
    @Resource
    private TradingApi tradingApi;
    @Resource
    private IOrdersCancelledService ordersCancelledService;
    @Resource
    private IOrdersRefundService ordersRefundService;

    /**
     * 预约下单
     *
     * @param placeOrderReqDTO 下单请求模型
     * @return 订单号
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public PlaceOrderResDTO placeOrder(PlaceOrderReqDTO placeOrderReqDTO) {
        //校验当前日期是否有预约设置
        ReservationSetting reservationSetting = reservationSettingService.queryByOrderDate(placeOrderReqDTO.getReservationDate());
        if (ObjectUtil.isEmpty(reservationSetting)) {
            throw new CommonException("当前日期不可预约");
        }

        //校验当前日期预约数量是否还有余额
        Integer reservations = Optional.ofNullable(reservationSetting.getReservations()).orElse(0);
        if (reservationSetting.getNumber() <= reservations) {
            throw new CommonException("当前日期预约已满");
        }

        //校验当前用户是否存在
        Member member = memberService.getById(UserThreadLocal.currentUserId());
        if (ObjectUtil.isEmpty(member)) {
            throw new CommonException("用户不存在");
        }

        //校验套餐是否存在
        Setmeal setmeal = setmealService.findById(placeOrderReqDTO.getSetmealId());
        if (ObjectUtil.isEmpty(setmeal)) {
            throw new CommonException("套餐不存在");
        }

        Orders orders = new Orders();
        orders.setOrderStatus(OrderStatusEnum.NO_PAY.getStatus());
        orders.setPayStatus(OrderPayStatusEnum.NO_PAY.getStatus());
        orders.setSortBy(System.currentTimeMillis());

        //套餐信息
        orders.setSetmealId(setmeal.getId());
        orders.setSetmealName(setmeal.getName());
        orders.setSetmealPrice(BigDecimal.valueOf(setmeal.getPrice()));
        orders.setSetmealSex(setmeal.getSex());
        orders.setSetmealAge(setmeal.getAge());
        orders.setSetmealImg(setmeal.getImg());
        orders.setSetmealRemark(setmeal.getRemark());

        //预约信息
        orders.setReservationDate(placeOrderReqDTO.getReservationDate());
        orders.setCheckupPersonName(placeOrderReqDTO.getCheckupPersonName());
        orders.setCheckupPersonSex(placeOrderReqDTO.getCheckupPersonSex());
        orders.setCheckupPersonPhone(placeOrderReqDTO.getCheckupPersonPhone());
        orders.setCheckupPersonIdcard(placeOrderReqDTO.getCheckupPersonIdcard());

        //当前用户信息
        orders.setMemberId(member.getId());
        orders.setMemberPhone(member.getPhone());

        //更新预约人数，自增1
        Integer result = reservationSettingService.updateReservations(reservationSetting.getId());
        if (result <= 0) {
            throw new CommonException("预约失败");
        }

        baseMapper.insert(orders);

        return new PlaceOrderResDTO(orders.getId());
    }

    /**
     * 用户端滚动分页查询
     *
     * @param ordersStatus 订单状态，0：未支付，100：待体检，200：已体检，300：已关闭，400：已取消
     * @param sortBy       排序字段
     * @return 分页结果
     */
    @Override
    public List<OrdersResDTO> memberPageQuery(Integer ordersStatus, Long sortBy) {
        //1.构件查询条件
        LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery()
                .eq(ObjectUtils.isNotNull(ordersStatus), Orders::getOrderStatus, ordersStatus)
                .lt(ObjectUtils.isNotNull(sortBy), Orders::getSortBy, sortBy)
                .eq(Orders::getMemberId, UserThreadLocal.currentUserId())
                .select(Orders::getId);
        Page<Orders> queryPage = new Page<>();
        queryPage.addOrder(OrderItem.desc("sort_by"));
        queryPage.setSearchCount(false);

        //2.查询订单id列表
        Page<Orders> ordersPage = baseMapper.selectPage(queryPage, queryWrapper);
        if (ObjectUtil.isEmpty(ordersPage.getRecords())) {
            return new ArrayList<>();
        }

        //3.提取订单id列表
        List<Long> ordersIds = CollUtils.getFieldValues(ordersPage.getRecords(), Orders::getId);

        //4.通过缓存您查询订单列表
        return cacheHelper.batchGet(String.format(RedisConstants.ORDER_PAGE_QUERY, UserThreadLocal.currentUserId()), ordersIds, (objectIds, clazz) -> {
            List<Orders> ordersList = baseMapper.selectBatchIds(objectIds);
            if (CollUtils.isEmpty(ordersList)) {
                return new HashMap<>();
            }

            return ordersList.stream().collect(Collectors.toMap(Orders::getId, o -> BeanUtil.toBean(o, OrdersResDTO.class)));
        }, OrdersResDTO.class, 600L);
    }

    /**
     * 用户端订单详情
     *
     * @param id 订单id
     * @return 订单详情
     */
    @Override
    public OrdersDetailResDTO getDetail(Long id) {
        Orders orders = baseMapper.selectById(id);
        OrdersDetailResDTO ordersDetailResDTO = BeanUtil.toBean(orders, OrdersDetailResDTO.class);

        //如果是取消或关闭状态，需要封装取消时间和取消原因
        if (ObjectUtil.equal(orders.getOrderStatus(), OrderStatusEnum.CLOSED.getStatus())
                || ObjectUtil.equal(orders.getOrderStatus(), OrderStatusEnum.CANCELLED.getStatus())) {
            OrdersCancelled ordersCancelled = ordersCancelledService.getById(id);
            ordersDetailResDTO.setCancelTime(ordersCancelled.getCancelTime());
            ordersDetailResDTO.setCancelReason(ordersCancelled.getCancelReason());
        }
        return ordersDetailResDTO;
    }

    /**
     * 订单支付
     *
     * @param id             订单id
     * @param tradingChannel 支付渠道：ALI_PAY、WECHAT_PAY
     * @return 订单支付响应体
     */
    @Override
    public OrdersPayResDTO pay(Long id, PayChannelEnum tradingChannel) {
        Orders orders = baseMapper.selectById(id);
        if (ObjectUtil.isNull(orders)) {
            throw new CommonException(TRADE_FAILED, "订单不存在");
        }
        //订单的支付状态为成功直接返回
        OrdersPayResDTO ordersPayResDTO = new OrdersPayResDTO();
        if (ObjectUtil.equals(OrderPayStatusEnum.PAY_SUCCESS.getStatus(), orders.getPayStatus())
                && ObjectUtil.isNotEmpty(orders.getTradingOrderNo())) {
            BeanUtil.copyProperties(orders, ordersPayResDTO);
            ordersPayResDTO.setProductOrderNo(orders.getId());
        } else {
            //生成二维码
            NativePayResDTO nativePayResDTO = generatQrCode(orders, tradingChannel);
            BeanUtil.copyProperties(nativePayResDTO, ordersPayResDTO);
        }
        return ordersPayResDTO;
    }

    //生成二维码
    private NativePayResDTO generatQrCode(Orders orders, PayChannelEnum tradingChannel) {

        //判断支付渠道
        Long enterpriseId = ObjectUtil.equal(PayChannelEnum.ALI_PAY, tradingChannel) ?
                tradeProperties.getAliEnterpriseId() : tradeProperties.getWechatEnterpriseId();

        //构建支付请求参数
        NativePayReqDTO nativePayReqDTO = new NativePayReqDTO();
        nativePayReqDTO.setProductOrderNo(orders.getId());
        nativePayReqDTO.setTradingChannel(tradingChannel);
        nativePayReqDTO.setTradingAmount(orders.getSetmealPrice());
        nativePayReqDTO.setEnterpriseId(enterpriseId);
        nativePayReqDTO.setMemo(orders.getSetmealName());
        nativePayReqDTO.setProductAppId(TradeConstants.PRODUCT_APP_ID);//指定支付来源是传智健康
        //判断是否切换支付渠道
        if (ObjectUtil.isNotEmpty(orders.getTradingChannel())
                && ObjectUtil.notEqual(orders.getTradingChannel(), tradingChannel.toString())) {
            nativePayReqDTO.setChangeChannel(true);
        }
        //生成支付二维码
        NativePayResDTO downLineTrading = nativePayApi.createDownLineTrading(nativePayReqDTO);
        //将交易单信息更新到订单中
        LambdaUpdateWrapper<Orders> updateWrapper = Wrappers.<Orders>lambdaUpdate()
                .eq(Orders::getId, orders.getId())
                .set(Orders::getTradingOrderNo, downLineTrading.getTradingOrderNo())
                .set(Orders::getTradingChannel, downLineTrading.getTradingChannel());
        super.update(updateWrapper);
        return downLineTrading;
    }

    /**
     * 请求支付服务查询支付结果
     *
     * @param id 订单id
     * @return 订单支付响应体
     */
    @Override
    public int getPayResultFromTradServer(Long id) {
        //1.查询订单表
        Orders orders = baseMapper.selectById(id);
        if (ObjectUtil.isNull(orders)) {
            throw new CommonException(TRADE_FAILED, "订单不存在");
        }

        //2.判断支付状态，已支付就直接返回
        Integer payStatus = orders.getPayStatus();
        if (ObjectUtil.notEqual(OrderPayStatusEnum.NO_PAY.getStatus(), payStatus)) {
            return payStatus;
        }

        //3.如果未支付，远程调用支付服务查询支付结果
        TradingResDTO tradingResDTO = tradingApi.findTradResultByTradingOrderNo(orders.getTradingOrderNo());
        if (ObjectUtil.isEmpty(tradingResDTO)) {
            throw new CommonException(TRADE_FAILED, "交易单不存在");
        }

        //如果第三方支付记录为未支付，直接返回
        if (ObjectUtil.notEqual(tradingResDTO.getTradingState(), TradingStateEnum.YJS)) {
            return payStatus;
        }

        //4.支付成功，更新订单
        paySuccess(tradingResDTO);

        //5.返回支付成功
        return OrderPayStatusEnum.PAY_SUCCESS.getStatus();
    }

    /**
     * 支付成功，更新订单
     *
     * @param tradingResDTO 第三方支付响应结果
     */
    @Override
    public void paySuccess(TradingResDTO tradingResDTO) {
        //清除订单缓存
        Orders orders = baseMapper.selectById(tradingResDTO.getProductOrderNo());
        String key = String.format(RedisConstants.ORDER_PAGE_QUERY, orders.getMemberId());
        cacheHelper.remove(key);

        //更新订单状态
        LambdaUpdateWrapper<Orders> updateWrapper = Wrappers.<Orders>lambdaUpdate()
                .eq(Orders::getId, tradingResDTO.getProductOrderNo())
                .eq(Orders::getOrderStatus, OrderStatusEnum.NO_PAY.getStatus())
                .set(Orders::getOrderStatus, OrderStatusEnum.WAITING_CHECKUP.getStatus())
                .set(Orders::getPayStatus, OrderPayStatusEnum.PAY_SUCCESS.getStatus())
                .set(Orders::getPayTime, LocalDateTime.now())
                .set(Orders::getTradingChannel, tradingResDTO.getTradingChannel())
                .set(Orders::getTradingOrderNo, tradingResDTO.getTradingOrderNo())
                .set(Orders::getTransactionId, tradingResDTO.getTransactionId());
        super.update(updateWrapper);
    }

    /**
     * 管理端分页查询
     *
     * @param ordersPageQueryReqDTO 分页查询请求
     * @return 分页结果
     */
    @Override
    public PageResult<OrdersResDTO> adminPageQuery(OrdersPageQueryReqDTO ordersPageQueryReqDTO) {
        //1.分页查询订单id列表
        Page<Long> ordersIdPage = adminPageQueryOrdersIdList(ordersPageQueryReqDTO);
        if (ObjectUtil.isEmpty(ordersIdPage.getRecords())) {
            return PageUtils.toPage(ordersIdPage, OrdersResDTO.class);
        }

        //2.根据订单id列表查询订单
        ordersPageQueryReqDTO.setIds(ordersIdPage.getRecords());
        List<Orders> ordersList = queryAndSortOrdersListByIds(ordersPageQueryReqDTO);
        List<OrdersResDTO> list = BeanUtil.copyToList(ordersList, OrdersResDTO.class);

        //3.封装响应结果
        return PageResult.<OrdersResDTO>builder()
                .total(ordersIdPage.getTotal())
                .pages(ordersIdPage.getPages())
                .list(list)
                .build();
    }

    /**
     * 管理端分页查询订单id列表
     *
     * @param ordersPageQueryReqDTO 订单分页查询请求
     * @return 订单id列表
     */
    private Page<Long> adminPageQueryOrdersIdList(OrdersPageQueryReqDTO ordersPageQueryReqDTO) {
        //1.构造查询条件
        Page<Orders> page = PageUtils.parsePageQuery(ordersPageQueryReqDTO, Orders.class);
        LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery()
                .eq(ObjectUtil.isNotEmpty(ordersPageQueryReqDTO.getMemberPhone()), Orders::getMemberPhone, ordersPageQueryReqDTO.getMemberPhone())
                .eq(ObjectUtil.isNotEmpty(ordersPageQueryReqDTO.getOrderStatus()), Orders::getOrderStatus, ordersPageQueryReqDTO.getOrderStatus())
                .select(Orders::getId);

        //2.分页查询
        Page<Orders> ordersPage = baseMapper.selectPage(page, queryWrapper);

        //3.封装结果，查询数据为空，直接返回
        Page<Long> orderIdsPage = new Page<>();
        BeanUtil.copyProperties(ordersPage, orderIdsPage, "records");
        if (ObjectUtil.isEmpty(ordersPage.getRecords())) {
            return orderIdsPage;
        }

        //4.查询结果不为空，提取订单id封装
        List<Long> orderIdList = ordersPage.getRecords().stream().map(Orders::getId).collect(Collectors.toList());
        orderIdsPage.setRecords(orderIdList);
        return orderIdsPage;
    }

    /**
     * 根据订单id列表查询并排序
     *
     * @param ordersPageQueryReqDTO 订单分页查询请求
     * @return 订单列表
     */
    private List<Orders> queryAndSortOrdersListByIds(OrdersPageQueryReqDTO ordersPageQueryReqDTO) {
        //1.构造查询条件
        Page<Orders> page = new Page<>();
        page.setSize(ordersPageQueryReqDTO.getPageSize());
        page.setOrders(PageUtils.getOrderItems(ordersPageQueryReqDTO, Orders.class));
        LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery()
                .in(Orders::getId, ordersPageQueryReqDTO.getIds());

        //2.分页查询
        page.setSearchCount(false);
        Page<Orders> ordersPage = baseMapper.selectPage(page, queryWrapper);
        if (ObjectUtil.isEmpty(ordersPage.getRecords())) {
            return Collections.emptyList();
        }

        return ordersPage.getRecords();
    }

    /**
     * 订单信息聚合
     *
     * @param id 订单id
     * @return 订单信息
     */
    @Override
    public AdminOrdersDetailResDTO aggregation(Long id) {
        Orders orders = baseMapper.selectById(id);

        //订单信息
        AdminOrdersDetailResDTO.OrderInfo orderInfo = BeanUtil.toBean(orders, AdminOrdersDetailResDTO.OrderInfo.class);

        //支付信息
        AdminOrdersDetailResDTO.PayInfo payInfo = new AdminOrdersDetailResDTO.PayInfo();
        if (ObjectUtil.equal(orders.getPayStatus(), OrderPayStatusEnum.NO_PAY.getStatus())) {
            payInfo.setPayStatus(OrderPayStatusEnum.NO_PAY.getStatus());
        } else {
            BeanUtil.copyProperties(orders, payInfo, "payStatus");
            payInfo.setPayStatus(OrderPayStatusEnum.PAY_SUCCESS.getStatus());
            payInfo.setThirdOrderId(orders.getTransactionId());
        }

        //取消信息
        AdminOrdersDetailResDTO.CancelInfo cancelInfo = new AdminOrdersDetailResDTO.CancelInfo();
        if (ObjectUtil.equal(orders.getOrderStatus(), OrderStatusEnum.CANCELLED.getStatus())) {
            OrdersCancelled ordersCancelled = ordersCancelledService.getById(id);
            cancelInfo.setCancelTime(ordersCancelled.getCancelTime());
            cancelInfo.setCancelReason(ordersCancelled.getCancelReason());
        }

        //退款信息
        AdminOrdersDetailResDTO.RefundInfo refundInfo = new AdminOrdersDetailResDTO.RefundInfo();
        if (ObjectUtil.equal(orders.getOrderStatus(), OrderStatusEnum.CLOSED.getStatus())) {
            refundInfo.setRefundStatus(orders.getPayStatus());
            refundInfo.setTradingChannel(orders.getTradingChannel());
            refundInfo.setRefundId(orders.getRefundId());

            OrdersCancelled ordersCancelled = ordersCancelledService.getById(id);
            refundInfo.setCancelTime(ordersCancelled.getCancelTime());
            refundInfo.setCancelReason(ordersCancelled.getCancelReason());
        }

        //封装返回结果
        AdminOrdersDetailResDTO adminOrdersDetailResDTO = new AdminOrdersDetailResDTO();
        adminOrdersDetailResDTO.setOrderInfo(orderInfo);
        adminOrdersDetailResDTO.setPayInfo(payInfo);
        adminOrdersDetailResDTO.setRefundInfo(refundInfo);
        adminOrdersDetailResDTO.setCancelInfo(cancelInfo);
        return adminOrdersDetailResDTO;
    }

    /**
     * 订单取消
     *
     * @param ordersCancelReqDTO 订单取消模型
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(OrdersCancelReqDTO ordersCancelReqDTO) {
        //1.获取当前用户信息
        CurrentUserInfo currentUserInfo = UserThreadLocal.currentUser();

        //2.构建订单取消记录
        OrdersCancelled ordersCancelled = new OrdersCancelled();
        ordersCancelled.setId(ordersCancelReqDTO.getId());
        ordersCancelled.setCancellerId(UserThreadLocal.currentUserId());
        ordersCancelled.setCancellerType(currentUserInfo.getUserType());
        ordersCancelled.setCancelTime(LocalDateTime.now());
        ordersCancelled.setCancelReason(ordersCancelReqDTO.getCancelReason());
        cancel(ordersCancelReqDTO.getId(), ordersCancelled);

        //清除订单缓存
        String key = String.format(RedisConstants.ORDER_PAGE_QUERY, UserThreadLocal.currentUserId());
        cacheHelper.remove(key);
    }

    /**
     * 订单取消
     *
     * @param id              订单id
     * @param ordersCancelled 订单取消模型
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(Long id, OrdersCancelled ordersCancelled) {
        //1.保存订单取消记录
        ordersCancelledService.save(ordersCancelled);

        //2.订单状态变更
        LambdaUpdateWrapper<Orders> updateWrapper = Wrappers.<Orders>lambdaUpdate()
                .eq(Orders::getId, id)
                .eq(Orders::getOrderStatus, OrderStatusEnum.NO_PAY.getStatus())
                .set(Orders::getOrderStatus, OrderStatusEnum.CANCELLED.getStatus());
        super.update(updateWrapper);
    }

    /**
     * 订单退款
     *
     * @param ordersCancelReqDTO 订单退款模型
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refund(OrdersCancelReqDTO ordersCancelReqDTO) {
        //1.获取当前用户信息、订单信息
        CurrentUserInfo currentUserInfo = UserThreadLocal.currentUser();
        Orders orders = baseMapper.selectById(ordersCancelReqDTO.getId());

        //校验退款时间
        if (orders.getPayTime().plusYears(1).isBefore(LocalDateTime.now())) {
            throw new CommonException("第三方支付不支持支付一年后退款");
        }

        //2.保存订单取消记录
        OrdersCancelled ordersCancelled = new OrdersCancelled();
        ordersCancelled.setId(orders.getId());
        ordersCancelled.setCancellerId(UserThreadLocal.currentUserId());
        ordersCancelled.setCancellerType(currentUserInfo.getUserType());
        ordersCancelled.setCancelTime(LocalDateTime.now());
        ordersCancelled.setCancelReason(ordersCancelReqDTO.getCancelReason());
        ordersCancelledService.save(ordersCancelled);

        //3.保存订单退款记录
        OrdersRefund ordersRefund = new OrdersRefund();
        ordersRefund.setId(ordersCancelReqDTO.getId());
        ordersRefund.setTradingOrderNo(orders.getTradingOrderNo());
        ordersRefund.setRealPayAmount(orders.getSetmealPrice());
        ordersRefundService.save(ordersRefund);

        //4.清除订单缓存
        String key = String.format(RedisConstants.ORDER_PAGE_QUERY, orders.getMemberId());
        cacheHelper.remove(key);

        //5.订单状态变更
        LambdaUpdateWrapper<Orders> updateWrapper = Wrappers.<Orders>lambdaUpdate()
                .eq(Orders::getId, ordersCancelReqDTO.getId())
                .eq(Orders::getOrderStatus, OrderStatusEnum.WAITING_CHECKUP.getStatus())
                .eq(Orders::getPayStatus, OrderPayStatusEnum.PAY_SUCCESS.getStatus())
                .set(Orders::getOrderStatus, OrderStatusEnum.CLOSED.getStatus())
                .set(Orders::getPayStatus, OrderPayStatusEnum.REFUNDING.getStatus());
        super.update(updateWrapper);
    }

    /**
     * 更新支付状态
     *
     * @param id        订单id
     * @param payStatus 支付状态
     * @param refundId  第三方支付的退款单号
     * @param refundNo  支付服务退款单号
     */
    @Override
    public void updateRefundStatus(Long id, Integer payStatus, String refundId, Long refundNo) {
        //清除订单缓存
        Orders orders = baseMapper.selectById(id);
        String key = String.format(RedisConstants.ORDER_PAGE_QUERY, orders.getMemberId());
        cacheHelper.remove(key);

        LambdaUpdateWrapper<Orders> updateWrapper = Wrappers.<Orders>lambdaUpdate()
                .eq(Orders::getId, id)
                .ne(Orders::getPayStatus, payStatus)
                .set(Orders::getPayStatus, payStatus)
                .set(ObjectUtil.isNotEmpty(refundId), Orders::getRefundId, refundId)
                .set(ObjectUtil.isNotEmpty(refundNo), Orders::getRefundNo, refundNo);
        super.update(updateWrapper);
    }

    /**
     * 查询超时订单id列表
     *
     * @param count 数量
     * @return 订单id列表
     */
    @Override
    public List<Orders> queryOverTimePayOrdersListByCount(Integer count) {
        LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery()
                .eq(Orders::getOrderStatus, OrderStatusEnum.NO_PAY.getStatus())
                .lt(Orders::getCreateTime, LocalDateTime.now().minusMinutes(15))
                .orderByAsc(Orders::getCreateTime)
                .last("LIMIT " + count);
        return baseMapper.selectList(queryWrapper);
    }

    /**
     * 根据状态统计数量
     *
     * @return 订单数量
     */
    @Override
    public OrdersCountResDTO countByStatus() {
        //1.根据状态分组统计数量
        List<OrderCountDTO> orderCountDTOList = baseMapper.countByStatus();
        OrdersCountResDTO ordersCountResDTO = new OrdersCountResDTO();
        if (CollUtil.isEmpty(orderCountDTOList)) {
            return ordersCountResDTO;
        }

        //2.封装不同状态订单数量
        Map<Integer, Integer> map = orderCountDTOList.stream().collect(Collectors.toMap(OrderCountDTO::getOrderStatus, OrderCountDTO::getCount));
        ordersCountResDTO.setNoPayCount(NumberUtils.null2Zero(map.get(OrderStatusEnum.NO_PAY.getStatus())));
        ordersCountResDTO.setWaitingCheckupCount(NumberUtils.null2Zero(map.get(OrderStatusEnum.WAITING_CHECKUP.getStatus())));
        ordersCountResDTO.setCompletedCheckupCount(NumberUtils.null2Zero(map.get(OrderStatusEnum.COMPLETED_CHECKUP.getStatus())));
        ordersCountResDTO.setClosedCount(NumberUtils.null2Zero(map.get(OrderStatusEnum.CLOSED.getStatus())));
        ordersCountResDTO.setCancelledCount(NumberUtils.null2Zero(map.get(OrderStatusEnum.CANCELLED.getStatus())));

        //3.计算订单总数，并封装
        int sum = orderCountDTOList.stream().mapToInt(OrderCountDTO::getCount).sum();
        ordersCountResDTO.setTotalCount(sum);

        return ordersCountResDTO;
    }
}
